package org.irri.smta.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class UploadUtils {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(UploadUtils.class);

	public class InputStreamKnownSizeBody extends InputStreamBody {
		private int length;

		public InputStreamKnownSizeBody(final InputStream in, final int length,
				final String mimeType, final String filename) {
			super(in, mimeType, filename);
			this.length = length;
		}

		@Override
		public long getContentLength() {
			return this.length;
		}
	}

	/**
	 * A generic method to execute any type of Http Request and constructs a
	 * response object
	 * 
	 * @param requestBase
	 *            the request that needs to be exeuted
	 * @return server response as <code>String</code>
	 */
	private static String executeRequest(HttpRequestBase requestBase)
			throws Exception {
		String responseString = "";

		HttpClient client = new DefaultHttpClient();
		client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
				HttpVersion.HTTP_1_1);
		try {
			HttpResponse response = client.execute(requestBase);
			HttpEntity responseEntity = response.getEntity();
			responseString = EntityUtils.toString(responseEntity, "UTF-8");
		} catch (ClientProtocolException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		} catch (IOException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		}
		client.getConnectionManager().shutdown();

		return responseString;
	}

	/**
	 * Method that builds the multi-part form data request
	 * 
	 * @param file
	 *            the actual file instance that needs to be uploaded
	 * @param urlString
	 *            the urlString to which the file needs to be uploaded
	 * @param username
	 *            the username
	 * @param password
	 *            the password
	 * @compressed true if file is gzip compressed; false otherwise
	 * @return server response as <code>String</code>
	 */
	private static String executeMultiPartRequest(File file, String urlString,
			String username, String password, boolean compressed)
			throws Exception {

		HttpPost postRequest = new HttpPost(urlString);
		try {

			MultipartEntity multiPartEntity = new MultipartEntity(
					HttpMultipartMode.BROWSER_COMPATIBLE);

			// The usual form parameters can be added this way
			multiPartEntity.addPart("username",
					new StringBody(username != null ? username : "",
							"text/plain", Charset.forName("UTF-8")));
			multiPartEntity.addPart("password",
					new StringBody(password != null ? password : "",
							"text/plain", Charset.forName("UTF-8")));
			multiPartEntity.addPart("compressed",
					new StringBody(compressed ? "y" : "n", "text/plain",
							Charset.forName("UTF-8")));

			/*
			 * Need to construct a FileBody with the file that needs to be
			 * attached and specify the MIME type of the file. Add the fileBody
			 * to the request as an another part. This part will be considered
			 * as file part and the rest of them as usual form-data parts
			 */
			byte bytes[] = FileUtils.readFileToByteArray(file);
			ByteArrayBody fileBody = new ByteArrayBody(bytes, null);
			multiPartEntity.addPart("xml", fileBody);
//			FileBody fileBody = new FileBody(file, "application/octet-stream");
//			multiPartEntity.addPart("xml", fileBody);

//			byte[] bytes = Files.toByteArray(file);
//			multiPartEntity.addPart("xml", new UploadUtils().new InputStreamKnownSizeBody(
//					new ByteArrayInputStream(bytes), bytes.length,
//					"application/octet-stream", file.getName()));

//			 FileInputStream inputStream = new FileInputStream(file);
//			 byte[] bytes = Files.toByteArray(file);
//			 ContentBody contentBody = new InputStreamBody(new ByteArrayInputStream(bytes),
//			 "application/octet-stream", file.getName());
			// ContentBody contentBody = new InputStreamBody(inputStream,
			// "binary/octet-stream", file.getName());
			// multiPartEntity.addPart("xml", contentBody);

			postRequest.setEntity(multiPartEntity);
		} catch (UnsupportedEncodingException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		}

		return executeRequest(postRequest);
	}

	private static String executeMultiPartRequest(String xml, String urlString,
			String username, String password, boolean compressed)
			throws Exception {

		HttpPost postRequest = new HttpPost(urlString);
		try {

			MultipartEntity multiPartEntity = new MultipartEntity(
					HttpMultipartMode.BROWSER_COMPATIBLE);

			// The usual form parameters can be added this way
			multiPartEntity.addPart("username",
					new StringBody(username != null ? username : "",
							"text/plain", Charset.forName("UTF-8")));
			multiPartEntity.addPart("password",
					new StringBody(password != null ? password : "",
							"text/plain", Charset.forName("UTF-8")));
			multiPartEntity.addPart("compressed",
					new StringBody(compressed ? "y" : "n", "text/plain",
							Charset.forName("UTF-8")));

			multiPartEntity.addPart("xml", new StringBody(xml != null ? xml
					: "", "text/plain", Charset.forName("UTF-8")));

			postRequest.setEntity(multiPartEntity);
		} catch (UnsupportedEncodingException e) {
			LOGGER.error(e.getMessage());
			throw new Exception(e);
		}

		return executeRequest(postRequest);
	}

//	private static String executeMultiPartRequest(Smta smta, File file,
//			String urlString, String username, String password,
//			boolean compressed) throws Exception {
//
//		HttpPost postRequest = new HttpPost(urlString);
//		try {
//
//			MultipartEntity multiPartEntity = new MultipartEntity(
//					HttpMultipartMode.BROWSER_COMPATIBLE);
//
//			// The usual form parameters can be added this way
//			multiPartEntity.addPart("username",
//					new StringBody(username != null ? username : "",
//							"text/plain", Charset.forName("UTF-8")));
//			multiPartEntity.addPart("password",
//					new StringBody(password != null ? password : "",
//							"text/plain", Charset.forName("UTF-8")));
//			multiPartEntity.addPart("compressed",
//					new StringBody(compressed ? "y" : "n", "text/plain",
//							Charset.forName("UTF-8")));
//
//			byte[] bytes = null;
//			try {
//				bytes = FileUtils.fileToByteArray(file);
//			} catch (Exception e) {
//				LOGGER.error(e.getMessage());
//				throw new Exception(e);
//			}
//			smta.getDocument().setPdf(bytes);
//
//			SmtaBuilder smtaBuilder = new SmtaBuilder();
//			String xml = "";
//			try {
//				xml = smtaBuilder.createXml(smta, "UTF-8");
//			} catch (Exception e) {
//				LOGGER.error(e.getMessage());
//				throw new Exception(e);
//			}
//			multiPartEntity.addPart("xml", new StringBody(xml != null ? xml
//					: "", "text/plain", Charset.forName("UTF-8")));
//
//			postRequest.setEntity(multiPartEntity);
//		} catch (UnsupportedEncodingException e) {
//			LOGGER.error(e.getMessage());
//			throw new Exception(e);
//		}
//
//		return executeRequest(postRequest);
//	}

	public static String postFile(File file, String urlString, String username,
			String password, boolean compressed) throws Exception {
		String response = UploadUtils.executeMultiPartRequest(file, urlString,
				username, password, compressed);
		return response;
	}

	public static String postXml(String xml, String urlString, String username,
			String password, boolean compressed) throws Exception {
		String response = UploadUtils.executeMultiPartRequest(xml, urlString,
				username, password, compressed);
		return response;
	}

//	public static String postSmta(Smta smta, File file, String urlString,
//			String username, String password, boolean compressed)
//			throws Exception {
//		String response = UploadUtils.executeMultiPartRequest(smta, file,
//				urlString, username, password, compressed);
//		return response;
//	}

}
